package com.easylinkin.linkappapi.lobar.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.utils.excel.ExcelReadUtil;
import com.easylinkin.linkappapi.lobar.dto.CompanyTree;
import com.easylinkin.linkappapi.lobar.dto.LaborCompanyProjectDTO;
import com.easylinkin.linkappapi.lobar.dto.excel.ExcelResultDTO;
import com.easylinkin.linkappapi.lobar.dto.excel.ExcelResultDetailDTO;
import com.easylinkin.linkappapi.lobar.entity.Group;
import com.easylinkin.linkappapi.lobar.entity.LaborCompany;
import com.easylinkin.linkappapi.lobar.entity.LaborCompanyProject;
import com.easylinkin.linkappapi.lobar.entity.UserProject;
import com.easylinkin.linkappapi.lobar.entity.vo.LaborCompanySelectVO;
import com.easylinkin.linkappapi.lobar.mapper.GroupMapper;
import com.easylinkin.linkappapi.lobar.mapper.LaborCompanyMapper;
import com.easylinkin.linkappapi.lobar.mapper.LaborCompanyProjectMapper;
import com.easylinkin.linkappapi.lobar.mapper.UserProjectMapper;
import com.easylinkin.linkappapi.lobar.service.LaborCompanyProjectService;
import com.easylinkin.linkappapi.lobar.util.UnifiedCodeValidator;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 闸机表 服务实现类
 * </p>
 *
 * @author kanyuanfeng
 * @since 2022-04-13
 */
@Service
public class LaborCompanyProjectServiceImpl extends ServiceImpl<LaborCompanyProjectMapper, LaborCompanyProject> implements LaborCompanyProjectService {

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Autowired
    private GroupMapper groupMapper;

    @Autowired
    private UserProjectMapper userProjectMapper;

    @Autowired
    private LaborCompanyMapper laborCompanyMapper;

    /**
     * 增加
     *
     * @param laborCompanyProject
     */
    @Override
    public void insert(LaborCompanyProject laborCompanyProject) {
        //设置基本属性
        laborCompanyProject.getIds().forEach(id -> {
            //删除之前添加过的
            QueryWrapper<LaborCompanyProject> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("company_id_", id)
                    .eq("tenant_id_", linkappUserContextProducer.getNotNullCurrent().getTenantId());
            baseMapper.delete(queryWrapper);

            LaborCompanyProject newCom = new LaborCompanyProject();
            newCom.setCompanyId(id);
            newCom.setCompanyName(laborCompanyProject.getCompanyName());
            newCom.setJoinTime(new Date());
            newCom.setStatus(1);
            this.setBase(newCom);
            this.save(newCom);
        });
    }

    /**
     * 根据id编辑
     *
     * @param laborCompanyProject
     */
    @Override
    public void updateOne(LaborCompanyProject laborCompanyProject) {
        /**
         * 验证重复
         */
        this.checkExist(laborCompanyProject);
        //设置基本属性
        this.setBase(laborCompanyProject);
        this.updateById(laborCompanyProject);
    }

    /**
     * @Description: 删除单位（包含批量删除）
     * @author kan yuanfeng
     * @date 2020/11/04 11:42
     */
    @Override
    public void delBatch(Set<String> ids) {
        //查询下面是否关联有班组
        ids.forEach(id -> {
            QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("company_project_id_", id).eq("delete_state_", 1);
            Integer integer = groupMapper.selectCount(queryWrapper);
            if (integer > 0) {
                throw new BusinessException("该单位下已有班组，请先删除班组");
            }
            UpdateWrapper<LaborCompanyProject> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("delete_state_", 0).set("status_", 0)
                    .eq("id", id);
            baseMapper.update(null, updateWrapper);
        });
    }

    /**
     * 组成一个树
     */
    @Override
    public List<CompanyTree> getTree(String groupName) {
        List<CompanyTree> companyTreeList = groupMapper.getTree(linkappUserContextProducer.getNotNullCurrent().getTenantId(), groupName);
        List<CompanyTree> newList = new ArrayList<>();
        if (null != companyTreeList && companyTreeList.size() > 0) {
            Map<String, List<CompanyTree>> map = companyTreeList.stream()
                    .collect(Collectors.groupingBy(CompanyTree::getParentId));
            map.forEach((k, v) -> {
                CompanyTree companyTree = new CompanyTree();
                companyTree.setId(k);
                companyTree.setName(v.get(0).getParentName());
                v.removeIf(r -> StringUtils.isBlank(r.getId()));
                companyTree.setCompanyTreeList(v);
                newList.add(companyTree);
            });
        }
        return newList;
    }

    /**
     * @Description: 进退场
     * @author kan yuanfeng
     * @date 2020/11/04 11:42
     */
    @Override
    public void updateStatus(LaborCompanyProject laborCompanyProject) {
        this.setBase(laborCompanyProject);
        if (Integer.valueOf(0).equals(laborCompanyProject.getStatus())) {
            laborCompanyProject.setLeaveTime(new Date());
        } else {
            laborCompanyProject.setJoinTime(new Date());
        }
        this.updateById(laborCompanyProject);
        if (Integer.valueOf(0).equals(laborCompanyProject.getStatus())) {
            //班组退场
            QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("company_project_id_", laborCompanyProject.getId())
                    .eq("status_", 1);
            List<Group> groups = groupMapper.selectList(queryWrapper);
            if (null != groups && groups.size() > 0) {
                List<String> groupIds = groups.stream().map(g -> g.getId()).collect(Collectors.toList());
                UpdateWrapper<Group> updateWrapper = new UpdateWrapper<>();
                updateWrapper.in("id", groupIds)
                        .eq("status_", 1)
                        .set("modify_time_", laborCompanyProject.getModifyTime())
                        .set("modify_id_", laborCompanyProject.getModifyId())
                        .set("status_", laborCompanyProject.getStatus())
                        .set("leave_time_", laborCompanyProject.getLeaveTime());
                groupMapper.update(null, updateWrapper);
                //人员退场
                UpdateWrapper<UserProject> userUpdateWrapper = new UpdateWrapper<>();
                userUpdateWrapper.in("group_id_", groupIds)
                        .eq("status_", 1)
                        .set("modify_time_", laborCompanyProject.getModifyTime())
                        .set("modify_id_", laborCompanyProject.getModifyId())
                        .set("status_", laborCompanyProject.getStatus())
                        .set("leave_time_", laborCompanyProject.getLeaveTime());
                userProjectMapper.update(null, userUpdateWrapper);
            }
        }
    }

    /**
     * 批量导入劳务公司
     * type = 1 为覆盖
     */
    @Override
    public ExcelResultDTO importExcel(MultipartFile file, String tenantId, Integer type)
            throws Exception {
        List<List<String>> excelList = ExcelReadUtil.getExcelInfo(file, 2, -1, -1);
        if (excelList.size() > 0 && excelList.get(0).size() < 6) {
            throw new BusinessException("模板错误,请选择正确的文件导入");
        }
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        //创建一个Set保存excel本身的身份证号码
        CompletableFuture<ExcelResultDTO> completableFuture = CompletableFuture
                .supplyAsync(() -> getExcelResultDTO(type, tenantId, excelList), executorService);
        ExcelResultDTO excelResultDTO = completableFuture.get();
        return excelResultDTO;
    }

    @Override
    public RestMessage queryCompanySelect() {
        LinkappUser linkappUser = linkappUserContextProducer.getCurrent();
        List<LaborCompanySelectVO> laborCompanySelectVOS = this.baseMapper.queryLaborCompanySelect(linkappUser.getTenantId());
        return RestBuilders.successBuilder().data(laborCompanySelectVOS).build();
    }

    /**
     * 执行导入和验证
     *
     * @param type
     * @param excelList
     * @return
     */
    private ExcelResultDTO getExcelResultDTO(Integer type, String tenantId, List<List<String>> excelList) {
        ExcelResultDTO excelResultDTO = new ExcelResultDTO();
        //异常数据组织返回
        List<ExcelResultDetailDTO> excelResultDetailDTOS = new ArrayList<>();
        //成功数据
        //重复数据
        //失败数据
        List<LaborCompany> laborCompanies = new ArrayList<>();

        //参建单位
        List<LaborCompanyProjectDTO> companies = this.getCompanies(tenantId);
        //参建单位资源数据
        List<LaborCompany> allCompany = laborCompanyMapper.selectList(new QueryWrapper<>());
        Set<String> nameSet = new HashSet<>();
        Set<String> codeSet = new HashSet<>();
        for (int i = 0; i < excelList.size(); i++) {
            ExcelResultDetailDTO excelResultDetailDTO = new ExcelResultDetailDTO();
            //异常提示信息
            List<String> msgs = new ArrayList<>();
            List<String> list = excelList.get(i);
            //验证塞数据
            LaborCompany laborCompany = new LaborCompany();
            //参建单位
            if (StringUtils.isBlank(list.get(0).trim())) {
                msgs.add("名称为空");
            } else if (nameSet.contains(list.get(0).trim())) {
                msgs.add("与表格中单位数据重复");
            } else {
                nameSet.add(list.get(0).trim());
            }
            laborCompany.setName(list.get(0).trim());

            //统一社会信用代码
            laborCompany.setCode(getCode(list.get(1).trim(), msgs, codeSet));
            //承建类型
            laborCompany.setBuildType(getBuildType(list.get(2).trim(), msgs));
            //单位简称
            laborCompany.setAbbreviation(getAbbreviation(list.get(3).trim(), msgs));
            laborCompany.setLegal(list.get(4).trim());
            //法人电话
            laborCompany.setLegalTelephone(getLegalTelephone(list.get(5).trim(), msgs));
            excelResultDetailDTO.setNo(i + 3);
            excelResultDetailDTO.setName(laborCompany.getName());
            //失败数据
            if (msgs.size() > 0) {
                excelResultDetailDTO.setDetail(StringUtils.join(msgs, ","));
                excelResultDetailDTO.setType(1);
                excelResultDetailDTO.setTypeName("失败");
            } else {
                //重复数据
                //查询参建单位是否重复
                long count = companies.stream().filter(c -> c.getName().equals(laborCompany.getName())
                                || laborCompany.getCode().equals(c.getCode()))
                        .count();
                if (count > 0) {
                    if (!Integer.valueOf(1).equals(type)) {
                        excelResultDetailDTO.setDetail("参建单位名称或统一社会信用代码重复");
                        excelResultDetailDTO.setType(2);
                        excelResultDetailDTO.setTypeName("重复");
                        excelResultDetailDTOS.add(excelResultDetailDTO);
                        continue;
                    } else {
                        ExcelResultDetailDTO repeat = new ExcelResultDetailDTO();
                        repeat.setName(excelResultDetailDTO.getName());
                        repeat.setNo(excelResultDetailDTO.getNo());
                        repeat.setDetail("单位信息覆盖");
                        repeat.setType(2);
                        repeat.setTypeName("覆盖");
                        excelResultDetailDTOS.add(repeat);
                    }
                }
                laborCompany.setTenantId(tenantId);
                laborCompanies.add(laborCompany);
            }
            excelResultDetailDTOS.add(excelResultDetailDTO);
        }
        //汇总
        excelResultDTO.setSum(excelList.size());
        excelResultDTO.setSuccess(laborCompanies.size());
        List<ExcelResultDetailDTO> repeat = excelResultDetailDTOS.stream()
                .filter(e -> Integer.valueOf(2).equals(e.getType())).collect(Collectors.toList());
        excelResultDTO.setRepeat(repeat.size());
        List<ExcelResultDetailDTO> fail = excelResultDetailDTOS.stream()
                .filter(e -> Integer.valueOf(1).equals(e.getType())).collect(Collectors.toList());
        excelResultDTO.setFail(fail.size());
        //去掉类型为空的
        excelResultDetailDTOS.removeIf(e -> null == e.getType());
        excelResultDTO.setExcelResultDetailDTOS(excelResultDetailDTOS);

        //保存数据
        insertList(laborCompanies, type, companies, allCompany);
        return excelResultDTO;
    }

    //保存数据
    private void insertList(List<LaborCompany> laborCompanies, Integer type, List<LaborCompanyProjectDTO> companies, List<LaborCompany> allCompany) {
        laborCompanies.forEach(l -> {
//      List<LaborCompany> companyList = allCompany.stream().filter(a -> a.getName().equals(l.getName()))
//          .collect(Collectors.toList());
            List<LaborCompany> companyList = allCompany.stream().filter(a -> l.getCode().equals(a.getCode()))
                    .collect(Collectors.toList());
            //如果是软删除更新其状态
            if (companyList.size() > 0) {
                //只更新一条
                LaborCompany laborCompany = companyList.get(0);
                QueryWrapper<LaborCompanyProject> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("company_id_", laborCompany.getId())
                        .eq("tenant_id_", l.getTenantId());
                List<LaborCompanyProject> laborCompanyProjects = baseMapper.selectList(queryWrapper);
                if (null != laborCompanyProjects && laborCompanyProjects.size() > 0) {
                    LaborCompanyProject laborCompanyProject = laborCompanyProjects.get(0);
                    laborCompanyProject.setModifyTime(new Date());
                    laborCompanyProject.setJoinTime(new Date());
                    laborCompanyProject.setDeleteState(1);
                    laborCompanyProject.setStatus(1);
                    baseMapper.updateById(laborCompanyProject);
                } else {
                    //新增
                    addOne(laborCompany);
                }
                //资源池
                if (Integer.valueOf(1).equals(type)) {
                    UpdateWrapper<LaborCompany> cUpdateWrapper = new UpdateWrapper<>();
                    cUpdateWrapper.set("name_", l.getName())
//              .set("register_time_",null)
//              .set("address",null)
//              .set("detailed_address_",null)
                            .set("legal_", l.getLegal())
                            .set("legal_telephone_", l.getLegalTelephone())
                            .set("abbreviation_", l.getAbbreviation())
                            .set("create_time_", new Date())
                            .set("modify_time_", new Date())
                            .set("build_type_", l.getBuildType())
                            .eq("id", laborCompany.getId());
                    laborCompanyMapper.update(null, cUpdateWrapper);
                }
            } else {
                l.setModifyTime(new Date());
                l.setCreateTime(new Date());
                laborCompanyMapper.insert(l);
                //保存关联关系
                addOne(l);
            }
        });
    }

    private void addOne(LaborCompany laborCompany) {
        LaborCompanyProject laborCompanyProject = new LaborCompanyProject();
        laborCompanyProject.setCompanyId(laborCompany.getId());
        laborCompanyProject.setCompanyName(laborCompany.getName());
        laborCompanyProject.setJoinTime(new Date());
        laborCompanyProject.setTenantId(laborCompany.getTenantId());
        laborCompanyProject.setStatus(1);
        this.setBase(laborCompanyProject);
        this.save(laborCompanyProject);
    }

    //法人电话
    private String getLegalTelephone(String value, List<String> msgs) {
        String tel = null;
        if (StringUtils.isNotBlank(value)) {
            Pattern pattern = Pattern.compile("[0-9]*");
            Matcher isNum = pattern.matcher(value);
            if (!isNum.matches() || value.length() != 11) {
                msgs.add("法人电话格式错误");
            } else {
                tel = value;
            }
        }
        return tel;
    }

    //单位简称
    private String getAbbreviation(String value, List<String> msgs) {
        String result = null;
        if (StringUtils.isBlank(value)) {
            msgs.add("单位简称为空");
        } else if (value.length() > 6) {
            msgs.add("单位简称长度超过6个字符");
        }
        result = value;
        return result;
    }

    //承建类型
    private String getBuildType(String value, List<String> msgs) {
        String result = null;
        if (StringUtils.isBlank(value)) {
            msgs.add("承建类型为空");
        } else {
            Map<String, Integer> typeMap = LaborCompany.getBuildTypeMap();
            if (!typeMap.containsKey(value)) {
                msgs.add("承建类型填写错误");
            } else {
                result = typeMap.get(value) + "";
            }
        }
        return result;
    }

    /**
     * 统一社会信用代码
     *
     * @param value
     * @param msgs
     * @return
     */
    private String getCode(String value, List<String> msgs, Set<String> codes) {
        String result = null;
        if (StringUtils.isBlank(value)) {
            msgs.add("统一社会信用代码为空");
        } else {
            boolean validate = UnifiedCodeValidator.codeValidate(value);
            if (!validate) {
                msgs.add("统一社会信用代码填写错误");
            } else if (codes.contains(value)) {
                msgs.add("与表格中统一社会信用代码重复");
            } else {
                codes.add(value);
                result = value;
            }
        }
        return result;
    }

    /**
     * 获取本项目的参建单位
     */
    private List<LaborCompanyProjectDTO> getCompanies(String tenantId) {
        Page page = new Page();
        page.setCurrent(1);
        page.setSize(-1);
        LaborCompanyProjectDTO laborCompany = new LaborCompanyProjectDTO();
        //项目id 过滤
        laborCompany.setTenantId(tenantId);
        IPage<LaborCompanyProjectDTO> laborCompanyProjectIPage = baseMapper.queryListByPage(page, laborCompany);
        List<LaborCompanyProjectDTO> companyProjectDTOS = laborCompanyProjectIPage.getRecords();
        return companyProjectDTOS;
    }

    @Override
    public IPage<LaborCompanyProjectDTO> queryListByPage(RequestModel<LaborCompanyProjectDTO> requestModel) {
        Page page = requestModel.getPage();
        LaborCompanyProjectDTO laborCompany = requestModel.getCustomQueryParams();
        //项目id 过滤
        //20221121变更，增加判断tenantId
        String tenantId = laborCompany.getTenantId();
        if (StringUtils.isBlank(tenantId)) {
            tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        }
        laborCompany.setTenantId(tenantId);
        IPage<LaborCompanyProjectDTO> laborCompanyProjectIPage = baseMapper.queryListByPage(page, laborCompany);
        if (null != laborCompanyProjectIPage.getRecords()) {
            laborCompanyProjectIPage.getRecords().forEach(l -> {
                //求班组数量
                QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("company_project_id_", l.getCompanyProjectId());
                List<Group> groups = groupMapper.selectList(queryWrapper);
                if (null != groups) {
                    l.setGroupNum(groups.size());
                    //求在线人数
                    List<String> groupIds = groups.stream().map(g -> g.getId()).collect(Collectors.toList());
                    if (groupIds.size() > 0) {
                        QueryWrapper<UserProject> userWrapper = new QueryWrapper<>();
                        userWrapper.eq("status_", 1)
                                .in("group_id_", groupIds);
                        Integer integer = userProjectMapper.selectCount(userWrapper);
                        l.setOnUserNum(null == integer ? 0 : integer);
                    }
                }
            });
        }
        return laborCompanyProjectIPage;
    }

    /**
     * 验证重复
     */
    private void checkExist(LaborCompanyProject laborCompanyProject) {
        QueryWrapper<LaborCompanyProject> queryWrapper = new QueryWrapper<>();
        //todo 设置判断重复条件
        //编辑的时候存在id
        Optional.ofNullable(laborCompanyProject.getId()).ifPresent(id -> queryWrapper.ne("id", laborCompanyProject.getId()));
        Integer integer = baseMapper.selectCount(queryWrapper);
        if (integer > 0) {
            throw new BusinessException("该闸机已存在");
        }
    }

    /**
     * 设置基本属性
     *
     * @param laborCompanyProject
     */
    private void setBase(LaborCompanyProject laborCompanyProject) {
        laborCompanyProject.setModifyTime(new Date());
        laborCompanyProject.setModifyId(linkappUserContextProducer.getCurrent().getId());
        //没有id就是新增,有就是编辑
        if (StringUtils.isBlank(laborCompanyProject.getId())) {
            laborCompanyProject.setCreatorId(linkappUserContextProducer.getCurrent().getId());
            laborCompanyProject.setCreateTime(new Date());
            if (StringUtils.isBlank(laborCompanyProject.getTenantId())) {
                laborCompanyProject.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
            }
        }
    }
}
